package org.jivesoftware.spark.crowd;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.spark.SparkManager;
import org.jivesoftware.spark.Workspace;
import org.jivesoftware.spark.crowd.impl.Crowd;
import org.jivesoftware.spark.crowd.packet.CrowdsIQManager;
import org.jivesoftware.spark.crowd.packet.ReceivedPacketProcesser;
import org.jivesoftware.spark.crowd.ui.CrowdChatRoom;
import org.jivesoftware.spark.crowd.ui.CrowdItem;
import org.jivesoftware.spark.crowd.ui.CrowdList;
import org.jivesoftware.spark.crowd.ui.UIEventManager;
import org.jivesoftware.spark.ui.ChatRoomNotFoundException;

/**
 * The main controller .
 * @author liyuan
 *
 */
public class CrowdsManager {
	
	private static CrowdsManager instance;
	/**
	 * 
	 */
	private static Map<String,Crowd> crowdsLocal = new HashMap<String,Crowd>();
	/**
	 * 
	 */
	private ReceivedPacketProcesser packetProcesser;
	/**
	 * 
	 * @return
	 */
	
	private UIEventManager uiEventManager;
	public static CrowdsManager getInstance(){
		if(instance == null)
			instance = new CrowdsManager();
		return instance;
	}
	/**
	 * 
	 */
	private CrowdsManager(){
		
		
	}
	public void init(){
		this.packetProcesser = ReceivedPacketProcesser.getInstance();
		this.uiEventManager = UIEventManager.getInstance();
		packetProcesser.init();
		uiEventManager.init();
	}
	/**
	 * 
	 * @param name
	 * @return
	 */
	public boolean createCrowd(String name){
		boolean created = true;
		//TODO
		return created;
	}
	/**
	 * 
	 * @param name
	 * @param reason
	 * @return
	 */
	public boolean destroyCrowd(String name,String reason){
		boolean destroyed = true;
		//TODO
		return destroyed;
	}
	/**
	 * apply for join in a crowd by sending an application
	 * 
	 * @param userName
	 * @param crowdName
	 * @return
	 */
	public boolean joinIn(String userName,String crowdName){
		boolean joinInSuccessful = true;
		//TODO
		return joinInSuccessful;
	}
	/**
	 * 
	 * @param userName
	 * @param crowdName
	 * @return
	 */
	public boolean quit(String JID,String crowdName)throws Exception{
		boolean quitSuccessful = true;
		Crowd crowd = findCrowdByName(crowdName);
		if(crowd == null)
			throw new Exception("quit failed : can't find the crowd in local crowds Collection!");
		crowd.removeMember(JID);
		
		
		return quitSuccessful;
	}
	/**
	 * Kick a member from the crowd.Only the crowd's creator can kick member
	 * @param userName
	 * @param crowdName
	 * @return
	 */
	public boolean kickMember(String userName,String crowdName){
		boolean kicked = true;
		//TODO
		return kicked;
	}
	/**
	 * By invoking this method,you will not receive any message from a member
	 * @param userName
	 * @param crowdName
	 * @return
	 */
	public boolean blockMember(String userName,String crowdName){
		boolean blocked = true;
		//TODO
		return blocked;
	}
	/**
	 * load all crowds this client have joined and make them shown on the {@link Workspace} tab pane {@link CrowdList}
	 * @return
	 */
	
	public void loadLocalCrowds()throws Exception{				
			new Thread(new Runnable(){
				@Override
				public void run() {
					try {
						CrowdsIQManager.getInstance(Param.getConnection(),Param.CROWD_SERVICE_NAME).loadLocalCrowds();
					} catch (Exception e) {
						e.printStackTrace();
					}					
				}				
			}).start();	
	}
	public void loadMembers(String crowdName)throws Exception{
		try {
			CrowdsIQManager.getInstance(Param.getConnection(),Param.CROWD_SERVICE_NAME).loadMembers(crowdName);
		} catch (Exception e) {
			
			e.printStackTrace();
			throw e;
		}
	}
	/**
	 * find all {@link Crowd} from the XMPP server by sending a special {@link Packet}
	 * @return
	 */
	public Collection<Crowd> getLocalCrowds(){
		
		return crowdsLocal.values();
	}
	/**
	 * find a {@link Crowd} according to its name from the XMPP server by sending a special {@link Packet}
	 * @return
	 */
	public Crowd findCrowdByNameFromServer(String name){
		Crowd crowd = null;
		//TODO
		return crowd; 
	}
	/**
	 * find a {@link Crowd} according to its name from local.
	 * @param name
	 * @return
	 */
	public Crowd findCrowdByName(String name){	
		
		return crowdsLocal.get(name);		
	}
	/**
	 * update a crowd's subject.
	 * only creator can change a crowd's subject .This method will send a {@link Packet} to server.
	 * @return true if success and false if failed
	 */
	public boolean updateSubject(String crowdName){
		boolean updated = true;
		//TODO
		return updated;
	}
	
	public Message sendMessage (String crowdName,String message)throws Exception{
		Crowd crowd = findCrowdByName(crowdName);
		if(crowd == null)
			throw new Exception("sendMessage failed : can't find this crowd from local crowds collection!");
		
		return crowd.sendMessage(message);
	}
	/**
	 * receive crowds on local client,contains:
	 * 1.loaded from the server when log in
	 * 2.loaded from the server when the client is running
	 * 3.the crowd which the user self created now
	 * 
	 * when crowds have been received,first,add them into crowdsLocal,then create {@link CrowdItem} and
	 * show them on the {@link Workspace}
	 * @param crowds
	 */
	public void receiveCrowdsLocal(List<Crowd> crowds) {
		CrowdList list = CrowdList.getInstance();
		for(Crowd c: crowds){
			if(!crowdsLocal.containsKey(c.getName())){
				crowdsLocal.put(c.getName(), c);
				
				CrowdItem crowdItem = new CrowdItem(c.getName(),Param.getCrowdIcon());
				crowdItem.initialize();			
								
				list.addCrowd(crowdItem);
			}
			else
				CrowdRecorder.record("CrowdsManager receiveCrowdsLocal error:already have a crowd having the same name!");
		}		
	}
	public void addCrowd(Crowd c){
		crowdsLocal.put(c.getName(), c);
		
	}
	public void filterOutgoingMessage(String m){
		//TODO 
	}
	
	
	public void addCrowdPresenceListener(String crowdName) {
		packetProcesser.addCrowdPresenceListener(crowdName);		
	}
	public UIEventManager getUIEventManager() {		
		return this.uiEventManager;
	}
	/**
	 * 
	 * @param crowdName
	 */
	public void removeCrowd(String crowdName) {
		if(crowdsLocal.containsKey(crowdName)){
			crowdsLocal.remove(crowdName);
			CrowdList.getInstance().removeCrowd(crowdName);
			
			try {
				CrowdChatRoom room = (CrowdChatRoom)Param.getChatContainer().getChatRoom(crowdName);
				
				room.leaveChatRoom();
			} catch (ChatRoomNotFoundException e) {
				
			}
		}
		
		
	}
}
